package com.ghostbusters.fingertrack.calibration;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.ghostbusters.fingertrack.wii.IRPoint;

public class Signature implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 6086113729992086097L;
	public double[][] matrix;
	private double[] rowspace;
	private int blur;
	private List<IRPoint> list;

	public Signature() {
		this(Calibration.BLUR);
	}

	public Signature(int blur) {
		this.blur = blur;
		list = new ArrayList<IRPoint>();
		matrix = new double[Calibration.CALIBRATION_SIZE + 1][Calibration.CALIBRATION_SIZE + 1];
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				matrix[i][j] = 0;
			}
		}
		rowspace = new double[(Calibration.CALIBRATION_SIZE + 1)
				* (Calibration.CALIBRATION_SIZE + 1)];
		for (int i = 0; i < rowspace.length; i++) {
			rowspace[i] = 0.0;
		}
	}

	public void addPoint(IRPoint point) {
		list.add(point);
		// for (int i = -blur; i <= blur; i++) {
		// for (int j = -blur; j <= blur; j++) {
		// if (((int) Math.round(scaledPoint.getX())) + i >= 0
		// && ((int) Math.round(scaledPoint.getY())) + j >= 0
		// && ((int) Math.round(scaledPoint.getX())) + i < matrix.length
		// && ((int) Math.round(scaledPoint.getY())) + j < matrix.length) {
		// matrix[((int) Math.round(scaledPoint.getX()))/* + i */][((int) Math
		// .round(scaledPoint.getY())) /* + j */] = 1;
		//
		// rowspace[(((int) Math.round(scaledPoint.getX())) /* + i */)
		// * matrix.length + ((int) Math.round(scaledPoint.getY())) /* + j */] =
		// 1;

		// }
		// }
		// }

	}

	public List<IRPoint> getList() {
		return list;
	}

	public void normalize() {
		normalize(Calibration.CALIBRATION_LENGTH, Calibration.CALIBRATION_SIZE);
	}

	/**
	 * Returns a signature that fits into a square of squareFactor by
	 * squareFactor
	 * 
	 * @param squareFactor
	 * @return the normalized signature
	 */
	public void normalize(int length, double squareFactor) {
		Signature sig2 = new Signature();
		double minX = getMinX(), minY = getMinY();
		double maxX = getMaxX() - minX, maxY = getMaxY() - minY;
		if (list.size() > 1)
			for (IRPoint point : list) {
				sig2.addPoint(new IRPoint((point.getX() - minX) / maxX
						* squareFactor, (point.getY() - minY) / maxY
						* squareFactor));
			}
		else
			sig2.setList(list);
		// Signature sig = new Signature();
		// // this part will make the same amount of points in each calibration
		// if (sig2.getList().size() > length) {
		// sig = new Signature();
		// double interval = (double) sig2.getList().size() / length;
		// for (double i = 0; i < sig2.getList().size(); i = i + interval) {
		// int index = (int) Math.round(i);
		// if (Math.round(i) == sig2.getList().size()) {
		// break;
		// }
		// sig.addPoint(sig2.getList().get((int) Math.round(index)));
		// }
		// } else {
		// sig.setList(sig2.getList());
		// }
		//
		list = sig2.getList();
	}

	public void generateBlurredMatrix(int n) {
		matrix = new double[Calibration.CALIBRATION_SIZE + 1][Calibration.CALIBRATION_SIZE + 1];
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				matrix[i][j] = 0;
			}
		}
		for (IRPoint point : list) {
			matrix[((int) Math.floor(point.getX()))][((int) Math.floor(point
					.getY()))] = 1;
			for (int i = -n; i <= n; i++) {
				for (int j = -n; j <= n; j++) {
					if (((int) Math.round(point.getX())) + i >= 0
							&& ((int) Math.round(point.getY())) + j >= 0
							&& ((int) Math.round(point.getX())) + i < matrix.length
							&& ((int) Math.round(point.getY())) + j < matrix.length)
						matrix[((int) Math.round(point.getX())) + i][((int) Math
								.round(point.getY())) + j] = 1;
				}
			}
		}
	}

	/**
	 * YOU CAN ONLY CALL THIS AFTER ADDING THE SIGNATURE TO A CALIBRATION
	 */
	public void generateRowspace() {

		// TODO: Make less intense
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix.length; j++) {
				rowspace[i * matrix.length + j] = matrix[i][j];
			}
		}
	}

	public double getMaxX() {
		double max = 0;
		for (IRPoint point : list) {
			if (point.getX() > max) {
				max = point.getX();
			}
		}
		return max;
	}

	public double getMaxY() {
		double max = 0;
		for (IRPoint point : list) {
			if (point.getY() > max) {
				max = point.getY();
			}
		}
		return max;
	}

	public double getMinX() {
		double min = Calibration.CALIBRATION_SIZE;

		for (IRPoint point : list) {
			if (point.getX() < min) {
				min = point.getX();
			}
		}
		return min;
	}

	public double getMinY() {
		double min = Calibration.CALIBRATION_SIZE;
		for (IRPoint point : list) {
			if (point.getY() < min) {
				min = point.getY();
			}
		}
		return min;
	}

	public double[] getRowspace() {
		return rowspace;
	}

	public void setList(List<IRPoint> list) {
		this.list = list;
	}

	public double[] getX() {
		double[] temp = new double[list.size()];
		for (int i = 0; i < temp.length; i++) {
			temp[i] = list.get(i).getX();
		}
		return temp;
	}

	public double[] getY() {
		double[] temp = new double[list.size()];
		for (int i = 0; i < temp.length; i++) {
			temp[i] = list.get(i).getY();
		}
		return temp;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		// sb.append("[");
		// for (int i = 0; i < matrix.length; i++) {
		// for (int j = 0; j < matrix.length; j++) {
		// sb.append(matrix[i][j] + ", ");
		// }
		// sb.append("\n");
		// }
		// sb.append("]");
		return list.toString();
	}
}
